<!DOCTYPE html>
<!-- saved from url=(0048) -->
<html lang="en" class="trancy-zh-CN"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>珠峰架构师成长计划</title>
    <link rel="stylesheet" type="text/css" href="./珠峰架构师成长计划_files/main.css">
    <style>
        .page-toc > ul .red {
            background: #f3f3f3;
            z-index: 1;
            border-left: 3px solid #009a61;
            -webkit-transition: all .2s ease;
            transition: all .2s ease;
            color: #000
        }
    </style>
    <style>
        html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td{margin:0;padding:0;border:0;outline:0;font-weight:inherit;font-style:inherit;font-family:inherit;font-size:100%;vertical-align:baseline}body{line-height:1;color:#000;background:#fff}ol,ul{list-style:none}table{border-collapse:separate;border-spacing:0;vertical-align:middle}caption,th,td{text-align:left;font-weight:normal;vertical-align:middle}a{text-decoration:inherit}a:hover{text-decoration:underline}a img{border:none}*{box-sizing:border-box}article,aside,canvas,details,figcaption,figure,footer,header,hgroup,menu,nav,section,summary,main{margin:0;padding:0;border:0;outline:0;display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}audio:not([controls]),[hidden]{display:none}.markdown-body{padding:30px 35px 30px 35px;word-wrap:break-word;font-family:"Helvetica Neue",Helvetica,"Segoe UI",Arial,freesans,sans-serif;font-size:16px;line-height:1.4em;color:#333}@media screen and (max-width:479px){.markdown-body{padding:30px 10px 30px 10px}}.markdown-body>*:first-child{margin-top:0 !important}.markdown-body strong{font-weight:bold}.markdown-body hr{border-top:1px solid #cacaca;border-width:1px 0 0 0}.markdown-body em{font-style:italic}.markdown-body img{max-width:100%}.markdown-body h1,.markdown-body h2,.markdown-body h3,.markdown-body h4,.markdown-body h5,.markdown-body h6{position:relative;margin-top:1em;margin-bottom:16px;font-weight:bold;line-height:1.4}.markdown-body h1 a,.markdown-body h2 a,.markdown-body h3 a,.markdown-body h4 a,.markdown-body h5 a,.markdown-body h6 a{display:none}.markdown-body h1:hover a,.markdown-body h2:hover a,.markdown-body h3:hover a,.markdown-body h4:hover a,.markdown-body h5:hover a,.markdown-body h6:hover a{display:inline;color:#000;font-size:85%}.markdown-body h1,.markdown-body h2{border-bottom:1px solid #eee}.markdown-body h1{font-size:2.25em;line-height:1.2;padding-bottom:.3em}.markdown-body h2{padding-bottom:.3em;font-size:1.75em;line-height:1.225;border-bottom:1px dashed #dedede}.markdown-body blockquote{padding:0 15px;color:#777;border-left:4px solid #ddd;margin:0}.markdown-body blockquote>:last-child{margin-bottom:0}.markdown-body blockquote>:first-child{margin-top:0}.markdown-body p,.markdown-body blockquote,.markdown-body ul,.markdown-body ol,.markdown-body dl,.markdown-body table,.markdown-body pre{margin-top:0;margin-bottom:16px}.markdown-body ul,.markdown-body ol{padding-left:1.4em;list-style:initial}.markdown-body ol{list-style-type:decimal}.markdown-body ol ol,.markdown-body ul ol{list-style-type:lower-roman}.markdown-body ul ul ol,.markdown-body ul ol ol,.markdown-body ol ul ol,.markdown-body ol ol ol{list-style-type:lower-alpha}.markdown-body pre{padding:16px;overflow:auto;background-color:#e5e5e5;border-radius:3px;word-break:break-all;word-wrap:break-word;font:16px Consolas,"Liberation Mono",Menlo,Courier,monospace}.markdown-body pre code{background-color:transparent;color:inherit;line-height:16px;display:block;font-size:14px}.markdown-body pre code:before,.markdown-body pre code:after,.markdown-body pre tt:before,.markdown-body pre tt:after{letter-spacing:0;content:""}.markdown-body code,.markdown-body tt{padding:0;padding-bottom:2px;margin:0 3px;vertical-align:top;background-color:#ededf7;border-radius:4px;padding-left:3px;padding-right:3px;font-size:14px;color:#6f5990}.markdown-body code:before,.markdown-body code:after,.markdown-body tt:before,.markdown-body tt:after{content:"\00a0";vertical-align:text-top}.markdown-body table{width:100%;border-collapse:collapse;border-spacing:0;max-width:100%;display:block;background-color:transparent}.markdown-body table th,.markdown-body table td{border:1px solid #ddd;padding:4px 10px}.markdown-body table th{font-weight:bold;background:#f3f3f3}.markdown-body table tr:nth-child(2n){background-color:#f8f8f8}.markdown-body table tbody{background:#fff}.markdown-body .task-list-item{padding:0}.markdown-body .task-list-item li{list-style-type:none}.hljs{display:block;overflow-x:auto;padding:.5em;color:#333;background:#f8f8f8;-webkit-text-size-adjust:none}.hljs-comment,.diff .hljs-header{color:#969896;font-size:90%}.hljs-keyword,.css .rule .hljs-keyword,.hljs-winutils,.nginx .hljs-title,.hljs-subst,.hljs-request,.hljs-status{color:#a71d5d;font-weight:bold}.hljs-number,.hljs-hexcolor,.ruby .hljs-constant{color:#008080}.hljs-string,.hljs-tag .hljs-value,.hljs-doctag,.tex .hljs-formula{color:#183691}.hljs-title,.hljs-id,.scss .hljs-preprocessor{color:#900;font-weight:bold}.hljs-list .hljs-keyword,.hljs-subst{font-weight:normal}.hljs-class .hljs-title,.hljs-type,.vhdl .hljs-literal,.tex .hljs-command{color:#458;font-weight:bold}.hljs-tag,.hljs-tag .hljs-title,.hljs-rule .hljs-property,.django .hljs-tag .hljs-keyword{color:#000080;font-weight:normal}.hljs-attribute,.hljs-variable,.lisp .hljs-body,.hljs-name{color:#008080}.hljs-regexp{color:#009926}.hljs-symbol,.ruby .hljs-symbol .hljs-string,.lisp .hljs-keyword,.clojure .hljs-keyword,.scheme .hljs-keyword,.tex .hljs-special,.hljs-prompt{color:#990073}.hljs-built_in{color:#0086b3}.hljs-preprocessor,.hljs-pragma,.hljs-pi,.hljs-doctype,.hljs-shebang,.hljs-cdata{color:#999;font-weight:bold}.hljs-deletion{background:#fdd}.hljs-addition{background:#dfd}.diff .hljs-change{background:#0086b3}.hljs-chunk{color:#aaa}*{box-sizing:border-box}body,html{height:100%;font-family:Helvetica,arial,nimbussansl,liberationsans,freesans,clean,sans-serif,"Segoe UI Emoji","Segoe UI Symbol"}.logo{float:left;padding:10px 20px 0 0;font-size:24px;color:#61dafb}.logo img{vertical-align:middle;margin:-4px 0 0 0}.nav{background:#20232a;z-index:2;height:80px;line-height:61px;border-bottom:1px solid #c4c4c4;padding:0 0 0 20px;position:fixed;width:100%}@media screen and (max-width:479px){.nav{height:initial;position:initial}}.nav ul{list-style:none;position:relative;display:inline-table;display:block;overflow-x:auto;height:100%}@media screen and (max-width:479px){.nav ul{display:-ms-inline-flexbox;display:inline-flex;width:100%;overflow:auto}}.nav ul ul{display:none;background:#d1d1d1;border-radius:0;padding:0;position:absolute;top:100%;z-index:9}.nav ul ul li.active a{color:#61dafb;line-height:29px;height:29px}.nav ul ul li{float:none;border-bottom:1px solid #c8c8c8;position:relative}.nav ul ul li a:hover{background:#4b545f;color:#fff}.nav ul ul a{color:#fff;line-height:29px;white-space:nowrap;word-break:keep-all}.nav ul ul ul{position:absolute;left:100%;top:0}.nav ul li{float:left;line-height:40px}.nav ul li a{color:#fff;text-decoration:none;padding:0 15px}.nav ul li:hover a{color:#61dafb}.nav ul li.active a{color:#61dafb;height:40px}.nav ul li:hover > ul{display:block}.nav ul:after{content:"";clear:both;display:block}.warpper{width:100%;padding:80px 0 0 0;height:100%;overflow:auto}@media screen and (max-width:479px){.warpper{padding-top:0}}.warpper .page-toc,.warpper .markdown-body{height:100%}.warpper .markdown-body{margin-left:220px;overflow:auto}@media screen and (max-width:479px){.warpper .markdown-body{margin-left:0}}.warpper .page-toc{width:200px;height:calc(100% - 80px);position:fixed;width:220px;border-right:1px solid #bbb;box-shadow:0 0 20px #ccc;background:#f7f7f7;padding:10px;overflow-y:auto;overflow-x:hidden;font-family:"Lucida Grande","Lucida Sans Unicode",Helvetica,Arial,sans-serif !important}@media screen and (max-width:479px){.warpper .page-toc{display:none}}.warpper .page-toc ul{list-style-type:none;margin:0}.warpper .page-toc ul a{display:block;padding:3px 0;color:#151515;text-decoration:none;font-weight:700;line-height:16px;font-size:14px}.warpper .page-toc ul a:hover{text-decoration:underline}.warpper .page-toc ul li{padding-left:3px;line-height:25px;text-align:left}.warpper .page-toc ul ul{margin:0 0 0 10px;padding:0 0 0 9px}.warpper .page-toc ul ul li a{font-size:90%;font-weight:normal;border-bottom:0;position:relative}.warpper .copyright{border-top:1px dashed #e9e9e9;padding:6px 0 5px 2px;margin:32px 0 0 0;line-height:16px;font-size:12px;color:#dfdfdf}.warpper .copyright a{color:#d6ddf8;text-decoration:underline}.warpper .copyright a:hover{color:#333}.forkgithub{position:absolute;z-index:2;right:0;background:url("../img/forkgithub.png") 14px -15px no-repeat}@media screen and (max-width:479px){.forkgithub{display:none}}.forkgithub a{display:block;width:149px;height:149px}.my-active{font-weight:bold !important;margin-top:-3px}.my-active:before{content:'';display:block;height:16px;border-left:4px solid #61dafb;padding-left:16px;position:absolute;left:-12px}::-webkit-scrollbar-track-piece{background-color:#fff;-webkit-border-radius:0}::-webkit-scrollbar{width:8px;height:8px}::-webkit-scrollbar-thumb{height:50px;background-color:#999;-webkit-border-radius:4px;outline:2px solid #fff;outline-offset:-2px;border:2px solid #fff}::-webkit-scrollbar-thumb:hover{height:50px;background-color:#9f9f9f;-webkit-border-radius:4px}
    </style>
</head>
<body>
<div class="nav">
    <div class="logo">
        
                珠峰架构师成长计划

    </div>
    <ul><li><a href="http://zhufengpeixun.com/nestjs/index.html">index</a></li><li><a href="http://zhufengpeixun.com/nestjs/html/1.fe.html">1.fe</a></li><li><a href="http://zhufengpeixun.com/nestjs/html/2.nest.html">2.nest</a></li><li><a href="http://zhufengpeixun.com/nestjs/html/3.decorator.html">3.decorator</a></li><li><a href="http://zhufengpeixun.com/nestjs/html/4.controller.html">4.controller</a></li><li><a href="http://zhufengpeixun.com/nestjs/html/5.ioc.html">5.ioc</a></li><li><a href="http://zhufengpeixun.com/nestjs/html/6.Providers.html">6.Providers</a></li><li><a href="http://zhufengpeixun.com/nestjs/html/7.middleware.html">7.middleware</a></li><li><a href="http://zhufengpeixun.com/nestjs/html/8.Exceptionfilters.html">8.Exceptionfilters</a></li><li><a href="http://zhufengpeixun.com/nestjs/html/9.Pipes.html">9.Pipes</a></li><li><a href="http://zhufengpeixun.com/nestjs/html/10.Guards.html">10.Guards</a></li><li><a href="http://zhufengpeixun.com/nestjs/html/11.Interceptors.html">11.Interceptors</a></li><li><a href="http://zhufengpeixun.com/nestjs/html/12.Upload.html">12.Upload</a></li><li><a href="http://zhufengpeixun.com/nestjs/html/13.cms-rbac.html">13.cms-rbac</a></li><li><a href="http://zhufengpeixun.com/nestjs/html/14.cms-content.html">14.cms-content</a></li><li><a href="http://zhufengpeixun.com/nestjs/html/15.cms-front.html">15.cms-front</a></li><li><a href="http://zhufengpeixun.com/nestjs/html/16.cms-refer.html">16.cms-refer</a></li><li class="active"><a href="">mysql2</a></li><li><a href="http://zhufengpeixun.com/nestjs/html/typeorm.html">typeorm</a></li><li><a href="http://zhufengpeixun.com/nestjs/html/logger.html">logger</a></li><li><a href="http://zhufengpeixun.com/nestjs/html/nestjs-i18n.html">nestjs-i18n</a></li><li><a href="http://zhufengpeixun.com/nestjs/html/Schematic.html">Schematic</a></li><li><a href="http://zhufengpeixun.com/nestjs/html/generator.html">generator</a></li><li><a href="http://zhufengpeixun.com/nestjs/html/htmx.html">htmx</a></li><li><a href="http://zhufengpeixun.com/nestjs/html/websocket.html">websocket</a></li><li><a href="http://zhufengpeixun.com/nestjs/html/etcd.html">etcd</a></li><li><a href="http://zhufengpeixun.com/nestjs/html/gRPC.html">gRPC</a></li><li><a href="http://zhufengpeixun.com/nestjs/html/microservices.html">microservices</a></li><li><a href="http://zhufengpeixun.com/nestjs/html/monorepo.html">monorepo</a></li><li><a href="http://zhufengpeixun.com/nestjs/html/graphql.html">graphql</a></li></ul></div>

  <div class="warpper">
    <span id="toc-toggle" style="position: fixed;left:10px;top:55px;z-index: 1000;color:white;background-color: rgb(32,35,42);">&lt;</span>
    <div class="page-toc">
      <ul><li><a href="#t01%20%E5%AE%89%E8%A3%85">1 安装</a></li><li><a href="#t12%20%E8%BF%9E%E6%8E%A5%E5%88%B0%E6%95%B0%E6%8D%AE%E5%BA%93">2 连接到数据库</a></li><li><a href="#t23%20%E6%89%A7%E8%A1%8C%E6%9F%A5%E8%AF%A2">3 执行查询</a><ul><li><a href="#t33.1%20%E5%9B%9E%E8%B0%83%E6%A8%A1%E5%BC%8F">3.1 回调模式</a></li><li><a href="#t43.2%20Promise%20%E6%A8%A1%E5%BC%8F">3.2 Promise 模式</a></li></ul></li><li><a href="#t54%20%E5%8F%82%E6%95%B0%E5%8C%96%E6%9F%A5%E8%AF%A2">4 参数化查询</a></li><li><a href="#t65%20%E8%BF%9E%E6%8E%A5%E6%B1%A0">5 连接池</a></li><li><a href="#t76%20%E4%BA%8B%E5%8A%A1%E5%A4%84%E7%90%86">6 事务处理</a></li></ul>
    </div>
    <div class="content markdown-body">
      <p><code>mysql2</code> 是一个用于 Node.js 的 MySQL 驱动，它提供了对 MySQL 数据库的连接和操作的高效接口。与官方的 <code>mysql</code> 模块相比，<code>mysql2</code> 更注重性能优化，并且在使用上提供了一些额外的功能。以下是对 <code>mysql2</code> 的一些关键特性的讲解：</p>
<h2 id="t01 安装">1 安装 <a href="#t01%20%E5%AE%89%E8%A3%85"> # </a></h2>
<p>首先，需要通过 npm 安装 <code>mysql2</code> 模块：</p>
<pre><code class="lang-bash">npm i --save-dev @types/node
npm install mysql2
</code></pre>
<h2 id="t12 连接到数据库">2 连接到数据库 <a href="#t12%20%E8%BF%9E%E6%8E%A5%E5%88%B0%E6%95%B0%E6%8D%AE%E5%BA%93"> # </a></h2>
<p>你可以通过 <code>createConnection</code> 方法创建一个连接：</p>
<pre><code class="lang-js"><span class="hljs-comment">// 引入 mysql2 模块</span>
<span class="hljs-keyword">const</span> mysql = <span class="hljs-built_in">require</span>(<span class="hljs-string">'mysql2'</span>);
<span class="hljs-comment">// 创建一个数据库连接</span>
<span class="hljs-keyword">const</span> connection = mysql.createConnection({
    <span class="hljs-attr">host</span>: <span class="hljs-string">'localhost'</span>,   <span class="hljs-comment">// 数据库主机名</span>
    <span class="hljs-attr">user</span>: <span class="hljs-string">'root'</span>,        <span class="hljs-comment">// 数据库用户名</span>
    <span class="hljs-attr">password</span>: <span class="hljs-string">'root'</span>,    <span class="hljs-comment">// 数据库用户密码</span>
    <span class="hljs-attr">database</span>: <span class="hljs-string">'orm'</span>      <span class="hljs-comment">// 数据库名称</span>
});
<span class="hljs-comment">// 连接到数据库</span>
connection.connect(<span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {
    <span class="hljs-comment">// 如果连接发生错误</span>
    <span class="hljs-keyword">if</span> (err) {
        <span class="hljs-comment">// 输出错误信息</span>
        <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Error connecting: '</span> + err.stack);
        <span class="hljs-keyword">return</span>;
    }
    <span class="hljs-comment">// 输出成功连接的信息，包括连接的线程ID</span>
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Connected as id '</span> + connection.threadId);
});
</code></pre>
<h2 id="t23 执行查询">3 执行查询 <a href="#t23%20%E6%89%A7%E8%A1%8C%E6%9F%A5%E8%AF%A2"> # </a></h2>
<p><code>mysql2</code> 支持两种查询模式：回调模式和 Promise 模式。</p>
<h3 id="t33.1 回调模式">3.1 回调模式 <a href="#t33.1%20%E5%9B%9E%E8%B0%83%E6%A8%A1%E5%BC%8F"> # </a></h3>
<pre><code class="lang-diff">const mysql = require('mysql2');
const connection = mysql.createConnection({
    host: 'localhost',
    user: 'root',
    password: 'root',
    database: 'orm'
});
connection.connect((err) =&gt; {
    if (err) {
        console.error('Error connecting: ' + err.stack);
        return;
    }
    console.log('Connected as id ' + connection.threadId);
});
<span class="hljs-addition">+connection.query('SELECT * FROM users WHERE id = ?', [1], (err, results, fields) =&gt; {</span>
<span class="hljs-addition">+    if (err) {</span>
<span class="hljs-addition">+        console.error(err);</span>
<span class="hljs-addition">+        return;</span>
<span class="hljs-addition">+    }</span>
<span class="hljs-addition">+    console.log(results); // 结果数组</span>
<span class="hljs-addition">+    console.log(fields);  // 字段信息数组</span>
<span class="hljs-addition">+});</span>
</code></pre>
<h3 id="t43.2 Promise 模式">3.2 Promise 模式 <a href="#t43.2%20Promise%20%E6%A8%A1%E5%BC%8F"> # </a></h3>
<p>为了使用 Promise 模式，你需要使用 <code>mysql2/promise</code>：</p>
<pre><code class="lang-js"><span class="hljs-comment">// 引入 mysql2/promise 模块以使用 Promise 接口</span>
<span class="hljs-keyword">const</span> mysql = <span class="hljs-built_in">require</span>(<span class="hljs-string">'mysql2/promise'</span>);

<span class="hljs-comment">// 定义一个异步函数来查询数据库</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">queryDatabase</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-comment">// 使用 await 等待创建数据库连接</span>
  <span class="hljs-keyword">const</span> connection = <span class="hljs-keyword">await</span> mysql.createConnection({
    <span class="hljs-attr">host</span>: <span class="hljs-string">'localhost'</span>,   <span class="hljs-comment">// 数据库主机名</span>
    <span class="hljs-attr">user</span>: <span class="hljs-string">'root'</span>,        <span class="hljs-comment">// 数据库用户名</span>
    <span class="hljs-attr">password</span>: <span class="hljs-string">'root'</span>,    <span class="hljs-comment">// 数据库用户密码</span>
    <span class="hljs-attr">database</span>: <span class="hljs-string">'orm'</span>      <span class="hljs-comment">// 数据库名称</span>
  });
  <span class="hljs-keyword">try</span> {
    <span class="hljs-comment">// 执行查询操作，获取查询结果和字段信息</span>
    <span class="hljs-keyword">const</span> [rows, fields] = <span class="hljs-keyword">await</span> connection.execute(<span class="hljs-string">'SELECT * FROM users WHERE id = ?'</span>, [<span class="hljs-number">1</span>]);
    <span class="hljs-comment">// 输出查询结果</span>
    <span class="hljs-built_in">console</span>.log(rows);
  } <span class="hljs-keyword">finally</span> {
    <span class="hljs-comment">// 确保在操作完成后关闭数据库连接</span>
    <span class="hljs-keyword">await</span> connection.end();
  }
}
<span class="hljs-comment">// 调用查询函数，并捕获可能的错误</span>
queryDatabase().catch(<span class="hljs-built_in">console</span>.error);
</code></pre>
<h2 id="t54 参数化查询">4 参数化查询 <a href="#t54%20%E5%8F%82%E6%95%B0%E5%8C%96%E6%9F%A5%E8%AF%A2"> # </a></h2>
<p><code>mysql2</code> 提供了安全的参数化查询，防止 SQL 注入攻击：</p>
<pre><code class="lang-diff">const mysql = require('mysql2');
const connection = mysql.createConnection({
    host: 'localhost',
    user: 'root',
    password: 'root',
    database: 'orm'
});
connection.connect((err) =&gt; {
    if (err) {
        console.error('Error connecting: ' + err.stack);
        return;
    }
    console.log('Connected as id ' + connection.threadId);
});
<span class="hljs-addition">+const userId = 1;</span>
<span class="hljs-addition">+connection.query('SELECT * FROM users WHERE id = ?', [userId], (err, results) =&gt; {</span>
<span class="hljs-addition">+    if (err) {</span>
<span class="hljs-addition">+        console.error(err);</span>
<span class="hljs-addition">+        return;</span>
<span class="hljs-addition">+    }</span>
<span class="hljs-addition">+    console.log(results);</span>
<span class="hljs-addition">+});</span>
</code></pre>
<h2 id="t65 连接池">5 连接池 <a href="#t65%20%E8%BF%9E%E6%8E%A5%E6%B1%A0"> # </a></h2>
<p>为了更高效地管理数据库连接，<code>mysql2</code> 支持连接池：</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> mysql = <span class="hljs-built_in">require</span>(<span class="hljs-string">'mysql2'</span>);
<span class="hljs-keyword">const</span> pool = mysql.createPool({
    <span class="hljs-attr">host</span>: <span class="hljs-string">'localhost'</span>,
    <span class="hljs-attr">user</span>: <span class="hljs-string">'root'</span>,
    <span class="hljs-attr">password</span>: <span class="hljs-string">'root'</span>,
    <span class="hljs-attr">database</span>: <span class="hljs-string">'orm'</span>,
    <span class="hljs-attr">waitForConnections</span>: <span class="hljs-literal">true</span>,
    <span class="hljs-attr">connectionLimit</span>: <span class="hljs-number">10</span>,
    <span class="hljs-attr">queueLimit</span>: <span class="hljs-number">0</span>
});

pool.query(<span class="hljs-string">'SELECT * FROM users WHERE id = ?'</span>, [<span class="hljs-number">1</span>], (err, results) =&gt; {
    <span class="hljs-keyword">if</span> (err) {
        <span class="hljs-built_in">console</span>.error(err);
        <span class="hljs-keyword">return</span>;
    }
    <span class="hljs-built_in">console</span>.log(results);
});
<span class="hljs-keyword">export</span> { }
</code></pre>
<h2 id="t76 事务处理">6 事务处理 <a href="#t76%20%E4%BA%8B%E5%8A%A1%E5%A4%84%E7%90%86"> # </a></h2>
<p>事务处理可以通过手动控制连接来实现：</p>
<pre><code class="lang-js"><span class="hljs-comment">// 引入 mysql2 模块</span>
<span class="hljs-keyword">const</span> mysql = <span class="hljs-built_in">require</span>(<span class="hljs-string">'mysql2/promise'</span>);
<span class="hljs-comment">// 创建一个连接池</span>
<span class="hljs-keyword">const</span> pool = mysql.createPool({
    <span class="hljs-attr">host</span>: <span class="hljs-string">'localhost'</span>,           <span class="hljs-comment">// 数据库主机名</span>
    <span class="hljs-attr">user</span>: <span class="hljs-string">'root'</span>,                <span class="hljs-comment">// 数据库用户名</span>
    <span class="hljs-attr">password</span>: <span class="hljs-string">'root'</span>,            <span class="hljs-comment">// 数据库用户密码</span>
    <span class="hljs-attr">database</span>: <span class="hljs-string">'orm'</span>,             <span class="hljs-comment">// 数据库名称</span>
    <span class="hljs-attr">waitForConnections</span>: <span class="hljs-literal">true</span>,    <span class="hljs-comment">// 等待连接数达到限制时是否等待</span>
    <span class="hljs-attr">connectionLimit</span>: <span class="hljs-number">10</span>,         <span class="hljs-comment">// 连接池中的最大连接数</span>
    <span class="hljs-attr">queueLimit</span>: <span class="hljs-number">0</span>,                <span class="hljs-comment">// 等待队列的最大数量，0 表示没有限制</span>
    <span class="hljs-attr">idleTimeout</span>: <span class="hljs-number">30000</span>,           <span class="hljs-comment">// 连接在空闲状态下的最长时间（毫秒），超时后将被释放</span>
    <span class="hljs-attr">acquireTimeout</span>: <span class="hljs-number">10000</span>,        <span class="hljs-comment">// 获取连接的超时时间（毫秒）</span>
});
<span class="hljs-comment">// 定义一个异步函数来执行事务</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">performTransaction</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-comment">// 获取连接池中的连接</span>
    <span class="hljs-keyword">const</span> connection = <span class="hljs-keyword">await</span> pool.getConnection();
    <span class="hljs-keyword">try</span> {
        <span class="hljs-comment">// 开始事务</span>
        <span class="hljs-keyword">await</span> connection.beginTransaction();
        <span class="hljs-comment">// 执行插入用户的 SQL 语句</span>
        <span class="hljs-keyword">const</span> [rows1] = <span class="hljs-keyword">await</span> connection.query(<span class="hljs-string">'INSERT INTO users (username) VALUES (?)'</span>, [<span class="hljs-string">'John'</span>]);
        <span class="hljs-comment">// 执行插入订单的 SQL 语句，使用插入用户的 ID</span>
        <span class="hljs-keyword">const</span> [rows2] = <span class="hljs-keyword">await</span> connection.query(<span class="hljs-string">'INSERT INTO orders (user_id, product) VALUES (?, ?)'</span>, [rows1.insertId, <span class="hljs-string">'Book'</span>]);
        <span class="hljs-built_in">console</span>.log(rows2);
        <span class="hljs-comment">// 提交事务</span>
        <span class="hljs-keyword">await</span> connection.commit();
    } <span class="hljs-keyword">catch</span> (err) {
        <span class="hljs-comment">// 如果有错误，回滚事务</span>
        <span class="hljs-keyword">await</span> connection.rollback();
        <span class="hljs-comment">// 输出错误信息</span>
        <span class="hljs-built_in">console</span>.error(err);
    } <span class="hljs-keyword">finally</span> {
        <span class="hljs-comment">// 释放连接回连接池</span>
        connection.release();
    }
}
<span class="hljs-comment">// 调用事务函数，并捕获可能的错误</span>
performTransaction().catch(<span class="hljs-built_in">console</span>.error);
<span class="hljs-comment">// 导出空对象（如果需要）</span>
<span class="hljs-keyword">export</span> { }
</code></pre>

    </div>
  </div>
  <div class="modal fade" id="loginModal" tabindex="-1" role="dialog" aria-labelledby="loginModalLabel">
    <div class="modal-dialog" role="document">
      <div class="modal-content">
        <div class="modal-header">
          <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
          <h4 class="modal-title" id="loginModalLabel">请登录</h4>
        </div>
        <div class="modal-body">
          <form>
            <div class="form-group">
              <label for="username" class="control-label">姓名:</label>
              <input type="text" class="form-control" id="username" placeholder="珠峰架构VIP会员系统用户名">
            </div>
            <div class="form-group">
              <label for="password" class="control-label">密码:</label>
              <input type="text" class="form-control" id="password" placeholder="珠峰架构VIP会员系统密码">
            </div>
          </form>
        </div>
        <div class="modal-footer">
          <button type="button" class="btn btn-default" data-dismiss="modal">登录</button>
        </div>
      </div>
    </div>
  </div>
  <script src="https://static.zhufengpeixun.com/jquerymin_1645176580555.js"></script>
  <script src="https://static.zhufengpeixun.com/bootstrapmin_1645176554753.js"></script>
  <script>
    function isPrime(num) {
      // 小于等于 1 的数都不是质数
      if (num <= 1) return false;
      // 2 是质数
      if (num === 2) return true;
      // 偶数除了2之外都不是质数
      if (num % 2 === 0) return false;
      // 从 3 开始，检查是否有小于等于 √num 的因数
      for (let i = 3; i <= Math.sqrt(num); i += 2) {
        if (num % i === 0) {
          return false;
        }
      }
      // 如果没有找到因数，则是质数
      return true;
    }

    let isLogin = localStorage.getItem('isLogin');
    if (isLogin) {

    } else {
      let zhufengjiagou = localStorage.getItem('zhufengjiagou');
      const host = 'http://login.zhufengpeixun.com';
      if (zhufengjiagou) {
        fetch(host + '/check', {
          method: "GET", mode: 'cors',
          headers: { 'Content-Type': 'application/json', authorization: `Bearer ${zhufengjiagou}` }
        }).then(response => response.json()).then(res => {
          if (res.success) {

          } else {
            $('#loginModal').modal('show')
          }
        })
      } else {
        $('#loginModal').modal('show')
      }
    }


    $('#loginModal').on('hidden.bs.modal', function (event) {
      var modal = $(this)
      let username = modal.find('.modal-body #username').val();
      let password = modal.find('.modal-body #password').val();
      if (!isNaN(username) && username.length >= 8 && isPrime(+username) && !isNaN(password) && password.length >= 8 && isPrime(+password)) {
        localStorage.setItem('isLogin', 'true');
        return;
      }
      fetch(host + '/login', {
        method: "POST", mode: 'cors',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ username, password })
      }).then(response => response.json()).then(res => {
        console.log(res);
        if (res.success) {
          localStorage.setItem('zhufengjiagou', res.zhufengjiagou);
        } else {
          window.location.href = 'http://www.zhufengpeixun.cn';
        }
      })
    })
  </script>
  <script>
  $('.warpper .page-toc ul ul li a').on('click', function () {
    $('.warpper .page-toc ul ul li a').removeClass('my-active')
    $(this).addClass('my-active')
  })
  $('.logo').on('mouseenter', function () {
    $('.nav').height('450px');
  })
  $('.nav').on('mouseleave', function () {
    $('.nav').height('80px');
  })
  $('.logo').on('click', function () {
    $('.nav').css('display', 'none');
    $('.warpper').css('padding', '0px');
  })
  $('#toc-toggle').on('click', function () {
    let width = $('.page-toc').width();
    if (width > 100) {
      $('.page-toc').width(0);
      $('.page-toc').css({
        'width': '0',
        'min-width': '0',
        'padding': '0',
        'border': 'none'
      });
      $('.content').css('margin-left', '0px');
      $(this).text('>');
    } else {
      $('.page-toc').width(200);
      $('.page-toc').css({
        'width': '200px',
        'min-width': '0',
        'padding': '0',
        'border': 'none'
      });
      $('.content').css('margin-left', '200px');
      $(this).text('<');
    }
  });
</script>


</body><link rel="stylesheet" asset="eduser.css" href="chrome-extension://mjdbhokoopacimoekfgkcoogikbfgngb/assets/eduser.css"></html>